﻿Imports iConverter.Models
Imports System.Text
Imports iConverter.Extensions


Namespace Core


    ''' <summary>
    ''' 编码转换器
    ''' </summary>
    ''' <remarks></remarks>
    Public Class EncodingConverter





        ''' <summary>
        ''' 后期处理插件集合
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Property Processers As New List(Of Processer)



        ''' <summary>
        ''' 发送到插件
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Property Send As Send = Nothing

        


        ''' <summary>
        ''' 设置 使用的插件
        ''' </summary>
        ''' <param name="processers">设置使用的后期处理插件</param>
        ''' <param name="send">设置发送到插件</param>
        ''' <remarks></remarks>
        Public Sub SetPlugins(Optional processers As IEnumerable(Of Processer) = Nothing,
                              Optional send As Send = Nothing)

            If Me.Processers Is Nothing AndAlso processers IsNot Nothing Then
                Me.Processers = New List(Of Processer)(processers)

            ElseIf Me.Processers Is Nothing AndAlso processers Is Nothing Then
                Me.Processers = New List(Of Processer)

            ElseIf  processers Is Nothing Then  'Me.Processers IsNot Nothing AndAlso 上边处理 Processer 为空，下边是非空的处理
                Me.Processers.Clear()
            Else
                Me.Processers.Clear()
                Me.Processers.AddRange(processers)
            End If

            Me.Send = send

        End Sub



        ''' <summary>
        ''' 转换文档编码
        ''' </summary>
        ''' <param name="doc">要转换的文档</param>
        ''' <exception cref="ArgumentNullException">当 doc 参数 为空的时候引发</exception>
        ''' <remarks></remarks>
        Public Sub Convert(ByVal doc As ConvertDocument)
            If doc Is Nothing Then
                Throw New ArgumentNullException("Doc")
            End If


            '文档编码  源编码，  目标编码   检查
            '当文档是Unicode时，跳过转换
            If Not doc.ContentEncoding.IsUnicodeEncoding OrElse Not SettingManager.Settings.isSkipUnicodeConversion Then



                '如果  文档编码 = 源编码 ，  则不转换（ 文档内容是正确的）
                If doc.ContentEncoding.Equals(doc.SourceEncoding) Then

                Else

                    If Not doc.IsChanged AndAlso doc.IsFromFile Then
                        '如果  文档 内容 来至文件 并且文档没有修改后， 则尝试 使用 源编码 从新读取文件
                        ConvertDocumentFactory.ReOpen(doc)

                    Else
                        '如果  文档编码 <> 源编码 ， 则 先用  文档编码，对文档做 还原， 再用 源编码进行解读

                        doc.Content = EncodingConverter.ReDncoding(doc.Content, doc.ContentEncoding, doc.SourceEncoding)


                    End If

                End If


                '当目标编码不是 Unicode类型时， 尝试转换编码。（暂定）
                'If Not doc.DestinationEncoding.IsUnicodeEncoding Then

                'End If


            End If


            '插件调用

            If Me.Processers IsNot Nothing AndAlso Me.Processers.Count > 0 Then
                For Each p In Me.Processers
                    Try
                        p.Processing(doc)

                    Catch ex As Exception
                        My.Log.WriteException(ex)
                    End Try
                Next
            End If

            If Me.Send IsNot Nothing Then
                Try
                    Me.Send.SendTo(doc)
                Catch ex As Exception
                    My.Log.WriteException(ex)
                End Try
            End If


            doc.SetIsConverteDone()


        End Sub


#Region "共享方法"


        ''' <summary>
        ''' 使用指定的编码器获取字节序列的字符串
        ''' </summary>
        ''' <param name="encode">要使用的编码器</param>
        ''' <param name="bytes">已用编码器编码后的字节序列</param>
        ''' <returns>返回已解码的字符串。 如果 bytes 为空（nothing）或长度为0 ，则返回 空串（“”）</returns>
        ''' <exception cref="ArgumentNullException">当编码器为空的时候引发</exception>
        ''' <remarks></remarks>
        Friend Shared Function GetString(ByVal encode As Encoding, ByVal bytes() As Byte) As String
            If encode Is Nothing Then
                Throw New ArgumentNullException()
            End If

            If bytes Is Nothing OrElse bytes.Length = 0 Then
                Return String.Empty
            End If

            Return encode.GetString(bytes)
        End Function


        ''' <summary>
        ''' 使用指定的编码器获取字符串的字节序列
        ''' </summary>
        ''' <param name="encode">要使用的编码器</param>
        ''' <param name="str">要获取字节序列的字符串</param>
        ''' <returns>返回已解码的字节序列。 如果 str 为空（nothing）或 空串（“”）或 空白 则返回 包含0个元素的字节数组</returns>
        ''' <exception cref="ArgumentNullException">当编码器为空的时候引发</exception>
        ''' <remarks></remarks>
        Friend Shared Function GetBytes(ByVal encode As Encoding, ByVal str As String) As Byte()
            If encode Is Nothing Then
                Throw New ArgumentNullException()
            End If

            If String.IsNullOrEmpty(str) OrElse String.IsNullOrWhiteSpace(str) Then
                Dim bytes(0) As Byte
                Return bytes
            End If

            Return encode.GetBytes(str)
        End Function



        ''' <summary>
        ''' 使用指定的编码器重新解码
        ''' </summary>
        ''' <param name="str">要解码的字符串</param>
        ''' <param name="strEncode">字符串使用的编码</param>
        ''' <param name="encode">用于重新解码的编码器</param>
        ''' <exception cref="ArgumentNullException">当编码器为空的时候引发</exception>
        ''' <returns>
        '''  如果 str 为空（nothing）或 空串（“”）或 空白 则返回 空串（“”）， 否则返回重新解码后的字符串
        ''' </returns>
        ''' <remarks>
        ''' 使用字符串编码对字符串还原成字节序列，并用指定的编码器重新解码。
        ''' 注：如果当前字符串的内容的编码和StrEncode一致，  则 使用 encode 编码器重新解读会后会乱码。
        ''' 但如果当前字符串的内容的编码和StrEncode相异（即有乱码）， 则使用 正确编码（Encode）重新解读后，即可消除乱码。
        ''' 通常strEncode是 系统编码
        ''' </remarks>
        Friend Shared Function ReDncoding(ByVal str As String, ByVal strEncode As Encoding, ByVal encode As Encoding) As String
            If encode Is Nothing OrElse strEncode Is Nothing Then
                Throw New ArgumentNullException()
            End If

            If String.IsNullOrEmpty(str) OrElse String.IsNullOrWhiteSpace(str) Then
                Return String.Empty
            End If

            If strEncode.Equals(encode) Then
                '相同的编码器，解读出来的字符串无变化
                Return str
            End If


            Dim bytes = GetBytes(strEncode, str)

            Return GetString(encode, bytes)

        End Function


        ''' <summary>
        ''' 将整个字节数组从一种编码转换为另一种编码。
        ''' </summary>
        ''' <param name="srcEncoding">bytes 的编码格式。</param>
        ''' <param name="dstEncoding">目标编码格式</param>
        ''' <exception cref="ArgumentNullException">当编码器为空的时候引发</exception>
        ''' <returns>
        ''' Byte 类型的数组包含将 bytes 从 srcEncoding 转换为 dstEncoding 的结果。 如果bytes  为空（nothing）或长度为0 ，则返回 包含0个元素的字节数组
        ''' </returns>
        ''' <remarks>
        ''' 备选方案，可能不去使用
        ''' </remarks>
        Friend Shared Function Convert(ByVal srcEncoding As Encoding, ByVal dstEncoding As Encoding, ByVal bytes() As Byte) As Byte()

            If srcEncoding Is Nothing OrElse dstEncoding Is Nothing Then
                Throw New ArgumentNullException()
            End If

            If bytes Is Nothing OrElse bytes.Length = 0 Then
                Dim b(0) As Byte
                Return b
            End If

            Return Encoding.Convert(srcEncoding, dstEncoding, bytes)
        End Function






#End Region


    End Class


End Namespace

